home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Chans / shell / shell.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  17.7 KB  |  790 lines

  1. /* shell.c: shell or program channel */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Chans/shell/RCS/shell.c,v 6.0 1991/12/18 20:11:52 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Chans/shell/RCS/shell.c,v 6.0 1991/12/18 20:11:52 jpo Rel $
  9.  *
  10.  * $Log: shell.c,v $
  11.  * Revision 6.0  1991/12/18  20:11:52  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. #include "util.h"
  19. #include "expand.h"
  20. #include "head.h"
  21. #include "qmgr.h"
  22. #include "q.h"
  23. #include "dr.h"
  24. #include "prm.h"
  25. #include "prog.h"
  26. #include    <sys/stat.h>
  27. #include    <fcntl.h>
  28. #include    <sys/wait.h>
  29. #include    <signal.h>
  30.  
  31. #ifdef __STDC__
  32. #define VOLATILE volatile
  33. #else
  34. #define VOLATILE
  35. #endif
  36.  
  37. #ifndef WCOREDUMP
  38. #define WCOREDUMP(x) (((union wait *)&(x))->w_coredump)
  39. #endif
  40. #ifndef WEXITSTATUS
  41. #define WEXITSTATUS(x) (((union wait *)&(x)) -> w_retcode)
  42. #endif
  43. #ifndef WTERMSIG
  44. #define WTERMSIG(x) (((union wait *)&(x)) -> w_termsig)
  45. #endif
  46.  
  47. extern void    sys_init(), err_abrt(), rd_end();
  48. extern struct type_Qmgr_DeliveryStatus    *delivery_resetDRs();
  49. extern char     *quedfldir;
  50. extern char    *chndfldir;
  51. extern char    *logdfldir;
  52. extern char    *ad_getlocal();
  53. extern CHAN     *ch_nm2struct();
  54. extern char    *expand_dyn ();
  55. extern void    or_myinit ();
  56. CHAN         *mychan;
  57. char        *this_msg = NULL, *this_chan = NULL;
  58. static int    first_successDR, first_failDR, err_fatal = FALSE;
  59. static int     data_bytes;
  60. static char    buf[BUFSIZ], *fatalbuf = NULLCP;
  61.  
  62. static struct type_Qmgr_DeliveryStatus *process ();
  63. static int toProcess ();
  64. static int processMsg ();
  65. static int doProcess ();
  66. static int write_to_child ();
  67. static int send_to_child();
  68. static int do_child_logging();
  69. static void set_success();
  70. static int initialise ();
  71. static char *get_adrstr();
  72. static int security_check ();
  73. static void dirinit ();
  74. static ADDR *getnthrecip ();
  75. static int    pipe_signaled;
  76. static jmp_buf    toplevel;
  77.  
  78. static SFD sig_pipe(sig)
  79. int sig;
  80. {
  81.     pipe_signaled = TRUE;
  82.     longjmp (toplevel, DONE);
  83. }
  84.  
  85. /*   */
  86. /* main routine */
  87.  
  88. main (argc, argv)
  89. int     argc;
  90. char    **argv;
  91. {
  92.     sys_init(argv[0]);
  93.     or_myinit();
  94.     dirinit ();
  95. #ifdef PP_DEBUG
  96.     if (argc>1 && (strcmp(argv[1],"debug") == 0))
  97.         debug_channel_control(argc,argv,initialise,process, NULLIFP);
  98.     else
  99. #endif
  100.         channel_control (argc, argv, initialise, process, NULLIFP);
  101. }
  102.  
  103. /*   */
  104. /* routine to move to correct place in file system */
  105.  
  106. static void dirinit ()
  107. {
  108.     if (chdir (quedfldir) < 0)
  109.         err_abrt (RP_LIO, " Unable to change directory to '%s'",
  110.               quedfldir);
  111. }
  112.  
  113. /*   */
  114. /* channel initialise routine */
  115.  
  116. static int initialise (arg)
  117. struct type_Qmgr_Channel *arg;
  118. {
  119.     char *name;
  120.     
  121.     name = qb2str(arg);
  122.  
  123.     if ((mychan = ch_nm2struct(name)) == NULLCHAN) {
  124.         PP_OPER(NULLCP, ("Chan/shell : Channel '%s' not known",name));
  125.         if (name != NULL) free(name);
  126.         return NOTOK;
  127.     }
  128.  
  129.     (void) signal (SIGCHLD, SIG_DFL);
  130.     if (name != NULL) free(name);
  131.     return OK;
  132. }
  133.  
  134. /*   */
  135. /* routine to check if allowed to filter this message through this channel */
  136. static int security_check (msg)
  137. struct type_Qmgr_ProcMsg *msg;
  138. {
  139.      char         *msg_file = NULL, *msg_chan = NULL;
  140.     int        result;
  141.  
  142.     result = TRUE;
  143.     msg_file = qb2str (msg->qid);    
  144.     msg_chan = qb2str (msg->channel);
  145.  
  146.     if ((mychan == NULLCHAN) || (strcmp(msg_chan,mychan->ch_name) != 0)) {
  147.         PP_LOG(LLOG_EXCEPTIONS,
  148.                ("Chans/shell channel err: '%s'",msg_chan));
  149.         result = FALSE;
  150.     }
  151.  
  152.     /* free all storage used */
  153.     if (msg_file != NULL) free(msg_file);
  154.     if (msg_chan != NULL) free(msg_chan);
  155.     return result;
  156. }
  157.  
  158. /*   */
  159. /* routine called to do shell */
  160.  
  161. Expand expand_macros[] = {
  162.     "SENDER", NULLCP,    /* 0 */
  163.     "822SENDER", NULLCP,    /* 1 */
  164.     "400SENDER", NULLCP,    /* 2 */
  165.     "QID", NULLCP,        /* 3 */
  166.     "UA-ID", NULLCP,    /* 4 */
  167.     "P1-ID", NULLCP,    /* 5 */
  168.     "RECIP", NULLCP,    /* 6 */
  169.     "822RECIP", NULLCP,    /* 7 */
  170.     "400RECIP", NULLCP,    /* 8 */
  171.     "RECIPIENT", NULLCP,    /* 9 */
  172.     "USERID", NULLCP,    /* 10 */
  173.     "GROUPID", NULLCP,    /* 11 */
  174.     "SIZE",    NULLCP,        /* 12 */
  175.     "CHANNELNAME", NULLCP,    /* 13 */
  176.     NULLCP, NULLCP};
  177.  
  178. static struct type_Qmgr_DeliveryStatus *process (arg)
  179. struct type_Qmgr_ProcMsg *arg;
  180. {
  181.     struct prm_vars    prm;
  182.     Q_struct    que;
  183.     char    sizebuf[20];
  184.     char    uidbuf[20], gidbuf[20];
  185.     ADDR        *sender = NULL;
  186.     ADDR        *recips = NULL;
  187.     int         rcount, retval;
  188.     struct type_Qmgr_UserList     *ix;
  189.     ADDR                *adr;
  190.     static char        *local = NULLCP;
  191.     char *key;
  192.     ProgInfo    *info = NULLPROG;
  193.  
  194.     bzero((char *) &que,sizeof(que));
  195.     bzero((char *) &prm,sizeof(prm));
  196.  
  197.     delivery_init(arg->users);
  198.     delivery_setall(int_Qmgr_status_messageFailure);
  199.     first_successDR = TRUE;
  200.     first_failDR = TRUE;
  201.     if (security_check(arg) != TRUE)
  202.         return deliverystate;
  203.  
  204.     if (this_msg != NULL) free(this_msg);
  205.     if (this_chan != NULL) free(this_chan);
  206.  
  207.     this_msg = qb2str(arg->qid);
  208.     this_chan = qb2str(arg->channel);
  209.  
  210.     PP_LOG(LLOG_NOTICE,
  211.            ("%s processing msg '%s'",mychan->ch_name,this_msg));
  212.  
  213.     if (rp_isbad(rd_msg(this_msg,&prm,&que,&sender,&recips,&rcount))) {
  214.         PP_LOG(LLOG_EXCEPTIONS,
  215.                ("%s rd_msg err: '%s'",mychan->ch_name,this_msg));
  216.         rd_end();
  217.         return delivery_setallstate(int_Qmgr_status_messageFailure,
  218.                         "Can't read message");
  219.     }
  220.  
  221.     expand_macros[0].expansion = que.Oaddress->ad_value;
  222.     expand_macros[1].expansion = que.Oaddress->ad_r822adr;
  223.     expand_macros[2].expansion = que.Oaddress->ad_r400adr;
  224.     expand_macros[3].expansion = this_msg;
  225.     expand_macros[4].expansion = que.ua_id;
  226.     expand_macros[5].expansion = que.msgid.mpduid_string;
  227.     /* 6-11 filled in below */
  228.     (void) sprintf (sizebuf, "%d", que.msgsize);
  229.     expand_macros[12].expansion = sizebuf;
  230.     expand_macros[13].expansion = mychan -> ch_name;
  231.  
  232.     if (arg->users == NULL)
  233.         PP_LOG(LLOG_NOTICE,
  234.             ("%s : passed a NULL user list for message '%s'",
  235.             mychan->ch_name,
  236.             this_msg));
  237.  
  238.     /* check each recipient for processing */
  239.     for (ix = arg->users; ix; ix = ix->next) {
  240.         err_fatal = FALSE;
  241.         if (fatalbuf != NULLCP) {
  242.             free(fatalbuf);
  243.             fatalbuf = NULLCP;
  244.         }
  245.         if ((adr = getnthrecip(&que,ix->RecipientId->parm)) == NULL) {
  246.             PP_LOG(LLOG_EXCEPTIONS,
  247.                    ("%s : failed to find recipient %d of msg '%s'",
  248.                 mychan->ch_name,ix->RecipientId->parm,
  249.                 this_msg));
  250.             delivery_setstate(ix->RecipientId->parm, 
  251.                       int_Qmgr_status_messageFailure,
  252.                       "Unable to find specified recipient");
  253.             continue;
  254.         }
  255.         buf[0] = '\0';
  256.         key = get_adrstr(adr);
  257.         if (local) {
  258.             free (local);
  259.             local = NULLCP;
  260.         }
  261.         if ((local = ad_getlocal(key, adr -> ad_type)) != NULLCP)
  262.             info = tb_getprog(local, mychan->ch_table);
  263.  
  264.         if (info == NULLPROG)
  265.             info = tb_getprog (key, mychan -> ch_table);
  266.         
  267.         if (info == NULLPROG) {
  268.             PP_LOG(LLOG_EXCEPTIONS,
  269.                    ("table lookup failed for '%s' in '%s'",
  270.                 key, mychan -> ch_table -> tb_name));
  271.             (void) sprintf (buf,
  272.                     "Failed to find entry for '%s' in table '%s'",
  273.                     key, mychan -> ch_table -> tb_name);
  274.             delivery_setstate(ix -> RecipientId -> parm,
  275.                      int_Qmgr_status_messageFailure,
  276.                      buf);
  277.             continue;
  278.         }
  279.  
  280.         expand_macros[6].expansion = adr -> ad_value;
  281.         expand_macros[7].expansion = adr -> ad_r822adr;
  282.         expand_macros[8].expansion = adr -> ad_r400adr;
  283.         expand_macros[9].expansion = local;
  284.         if (info -> username)
  285.             expand_macros[10].expansion = info -> username;
  286.         else {
  287.             (void) sprintf (uidbuf, "%d", info -> uid);
  288.             expand_macros[10].expansion = uidbuf;
  289.         }
  290.         (void) sprintf (gidbuf, "%d", info -> gid);
  291.         expand_macros[11].expansion = gidbuf;
  292.  
  293.         
  294.         switch (lchan_acheck (adr, mychan, 1, NULLVP)) {
  295.             default:
  296.             case NOTOK:
  297.             break;
  298.             case OK:
  299.             if (processMsg(this_msg, adr, info) == NOTOK) {
  300.                 if (err_fatal == TRUE) {
  301.                     /* DR it */
  302.                     set_1dr (&que, adr->ad_no, this_msg,
  303.                          DRR_TRANSFER_FAILURE,
  304.                          DRD_UA_UNAVAILABLE,
  305.                          fatalbuf);
  306.                     delivery_set (adr->ad_no,
  307.                               (first_failDR == TRUE) ? int_Qmgr_status_negativeDR : int_Qmgr_status_failureSharedDR);
  308.                     first_failDR = FALSE;
  309.                 } else {
  310.                     PP_LOG(LLOG_EXCEPTIONS,
  311.                            ("%s : failed to process msg '%s' for recip '%d' on channel '%s'",
  312.                         mychan->ch_name,this_msg, adr->ad_no, this_chan));
  313.                     delivery_setstate(adr->ad_no, 
  314.                               int_Qmgr_status_messageFailure,
  315.                               buf);
  316.                 }
  317.             } else {
  318.                 PP_LOG(LLOG_NOTICE,
  319.                        ("%s : processed '%s' for recipient %d",
  320.                     mychan->ch_name,this_msg,adr->ad_no));
  321.                 set_success(adr, &que);
  322.             }
  323.         }
  324.         prog_free (info);
  325.         info = NULLPROG;
  326.     }
  327.     if (fatalbuf != NULLCP) {
  328.         free(fatalbuf);
  329.         fatalbuf = NULLCP;
  330.     }
  331.  
  332.     if (rp_isbad(retval = wr_q2dr(&que, this_msg))) {
  333.         PP_LOG(LLOG_EXCEPTIONS,
  334.                ("%s wr_q2dr failure '%d'",mychan->ch_name,retval));
  335.         delivery_resetDRs(int_Qmgr_status_messageFailure);
  336.     }
  337.  
  338.     rd_end();
  339.     return deliverystate;
  340. }
  341.  
  342. static void set_success(recip, que)
  343. ADDR        *recip;
  344. Q_struct    *que;
  345. {
  346.     if (recip->ad_usrreq == AD_USR_CONFIRM ||
  347.         recip->ad_mtarreq == AD_MTA_CONFIRM ||
  348.         recip->ad_mtarreq == AD_MTA_AUDIT_CONFIRM) {
  349.         set_1dr(que, recip->ad_no, this_msg,
  350.             DRR_NO_REASON, -1, NULLCP);
  351.         delivery_set(recip->ad_no, 
  352.                  (first_successDR == TRUE) ?
  353.                  int_Qmgr_status_positiveDR :
  354.                  int_Qmgr_status_successSharedDR);
  355.     } else {
  356.         (void) wr_ad_status(recip, AD_STAT_DONE);
  357.         (void) wr_stat (recip, que, this_msg, data_bytes);
  358.         delivery_set(recip->ad_no, int_Qmgr_status_success);
  359.     }
  360. }
  361.  
  362. /*   */
  363. static int toProcess (msg, recip)
  364. /* returns true if should process msg for recip on mychan */
  365. char    *msg;
  366. ADDR     *recip;
  367. {
  368.     LIST_RCHAN    *chan;
  369.     if ((chan = recip->ad_outchan) == NULL) {
  370.         PP_OPER(NULLCP,
  371.             ("%s : no outbound channel specified for recipient %d of msg '%s'",
  372.              mychan -> ch_name,
  373.              recip->ad_no,
  374.              msg));
  375.         exit(1);
  376.     }
  377.             
  378.     if (strcmp(chan->li_chan->ch_name, mychan->ch_name) == 0)
  379.         return TRUE;
  380.     else {
  381.         PP_LOG(LLOG_EXCEPTIONS,
  382.                ("Channel mismatch for recip %d of msg '%s'",
  383.             recip->ad_no,
  384.             msg));
  385.         return FALSE;
  386.     }
  387. }    
  388.  
  389. /*   */
  390. static int processMsg (msg,recip, info)
  391. /* returns OK if managed to process msg for recip on mychan */
  392. char    *msg;
  393. ADDR     *recip;
  394. ProgInfo *info;
  395. {
  396.     char     *origdir = NULL;
  397.     int result = OK;
  398.     char    file[MAXPATHLENGTH];
  399.     
  400.     if (qid2dir(msg, recip, TRUE, &origdir) != OK) {
  401.         PP_LOG(LLOG_EXCEPTIONS,
  402.                ("%s no message directory for recip %d of message '%s'",
  403.             mychan->ch_name,recip->ad_no, msg));
  404.         (void) sprintf(buf,
  405.                    "Unable to find source directory");
  406.         result = NOTOK;
  407.     }
  408.  
  409.     if (info->solo == TRUE) {
  410.         msg_rinit(origdir);
  411.         while (result == OK && msg_rfile(file) == RP_OK)
  412.             if (doProcess(file, info) != OK)
  413.                 result = NOTOK;
  414.         msg_rend();
  415.     } else {
  416.         if ((result == OK) && (doProcess(origdir, info) != OK))
  417.             result = NOTOK;
  418.     }
  419.  
  420.     if (origdir != NULL) free(origdir);
  421.     return result;
  422. }
  423.  
  424. /*   */
  425.  
  426. static int sigpiped, sigalarmed;
  427. static SFD alarmed(), piped();
  428. static jmp_buf pipe_alrm_jmp;
  429. static char env_home[LINESIZE], env_user[LINESIZE], env_shell[LINESIZE];
  430. static char *env[] = {
  431.     env_home, env_user, env_shell, NULLCP
  432.     };
  433.  
  434. extern char *dupfpath ();
  435. /* processes orig directory contents through mychan */
  436. static int doProcess (orig, info)
  437. char    *orig;    /* original directory */
  438. ProgInfo *info;
  439. {
  440.     int    fd[2],
  441.         fd_stderr[2],
  442.         result = OK,
  443.         pid,
  444.         pgmresult;
  445.     char    *expanded,
  446.         *program = NULL,
  447.         *margv[20];
  448.     SFP    oldalarm, oldpipe;
  449.     VOLATILE int    killed = 0;
  450.     struct stat statbuf;
  451.  
  452.     if ((expanded = expand_dyn (info->cmd_line, expand_macros)) == NULLCP) {
  453.         PP_OPER (NULLCP,
  454.             ("%s : failed to expand '%s'", info->cmd_line));
  455.         (void) sprintf(buf,
  456.                    "Failed to expand '%s'",
  457.                    info -> cmd_line);
  458.         return NOTOK;
  459.     }
  460.  
  461.     PP_NOTICE(("%s",expanded));
  462.     if (sstr2arg(expanded, 20, margv, " \t") < 1) {
  463.         PP_OPER(NULLCP, ("%s : no arguments in info string",
  464.              mychan->ch_name));
  465.         (void) sprintf (buf,
  466.                 "No arguments in info string '%s'",
  467.                 expanded);
  468.         free(expanded);
  469.         return NOTOK;
  470.     }
  471.  
  472.     program = dupfpath (chndfldir, margv[0]);
  473.     
  474.     if (stat(program, &statbuf) != OK) {
  475.         PP_OPER(NULLCP, ("%s : missing program '%s'",
  476.              mychan -> ch_name, program));
  477.         (void) sprintf (buf,
  478.                 "Missing program '%s",
  479.                 program);
  480.         free(expanded);
  481.         return NOTOK;
  482.     }
  483.     (void) sprintf (env_home, "HOME=%s", info -> home);
  484.     (void) sprintf (env_user, "USER=%s", info -> username ?
  485.             info -> username : "anon");
  486.     (void) sprintf (env_shell, "SHELL=%s", info -> shell);
  487.  
  488.     if (pipe(fd) != 0) {
  489.         PP_SLOG(LLOG_EXCEPTIONS, "pipe",
  490.                ("pipe failed"));
  491.         (void) sprintf(buf,
  492.                    "Pipe failed");
  493.         free(expanded);
  494.         return NOTOK;
  495.     }
  496.     if (pipe(fd_stderr) != 0) {
  497.         PP_SLOG(LLOG_EXCEPTIONS, "pipe",
  498.                ("stderr pipe failed"));
  499.         free(expanded);
  500.         (void) sprintf (buf,
  501.                 "standard error pipe failed");
  502.         (void) close (fd[0]);
  503.         (void) close (fd[1]);
  504.         return NOTOK;
  505.     }
  506.     if ((pid = tryfork()) == 0) {
  507.         /* in child so redirect input and stderr */
  508.         (void) dup2 (fd[0], 0);
  509.         (void) dup2 (fd_stderr[1], 1);
  510.         (void) dup2 (fd_stderr[1], 2);
  511.         (void) close(fd[0]);
  512.         (void) close(fd[1]);
  513.         (void) close(fd_stderr[0]);
  514.         (void) close(fd_stderr[1]);
  515.         (void) setpgrp(0, getpid());
  516.  
  517.         if(chdir (info -> home) == NOTOK)
  518.             chdir ("/tmp");
  519.  
  520.         if (info -> username)
  521.             (void) initgroups (info -> username, info -> gid);
  522. #ifdef SYS5
  523.         if (setgid (info->gid) == -1 ||
  524.             setuid (info->uid) == -1) {
  525. #else
  526.         if (setregid (info->gid, info->gid) == -1 ||
  527.             setreuid (info->uid, info->uid) == -1) {
  528. #endif
  529.             PP_SLOG (LLOG_EXCEPTIONS, "user",
  530.                  ("Can't set uid/gid %d/%d",
  531.                   info -> uid, info -> gid));
  532.             _exit(1);
  533.         }
  534.  
  535.         execve (program,margv, env);
  536.         _exit (1);
  537.  
  538.     } else if (pid == -1) {
  539.         PP_SLOG(LLOG_EXCEPTIONS, this_msg,
  540.                ("tryfork failed"));
  541.         (void) sprintf(buf,
  542.                    "Tryfork failed");
  543.         (void) close(fd_stderr[1]);
  544.         (void) close(fd[1]);
  545.         (void) close(fd_stderr[0]);
  546.         (void) close(fd[0]);
  547.         result = NOTOK;
  548.     } else {
  549. #ifdef SVR4
  550.         int w;
  551. #else
  552.         union wait w;
  553. #endif
  554.         
  555.         (void) close(fd_stderr[1]);
  556.         (void) close(fd[0]);
  557.         
  558.         data_bytes = 0;
  559.         oldalarm = signal(SIGALRM, alarmed);
  560.         oldpipe = signal(SIGPIPE, piped);
  561.         sigpiped = 0;
  562.         sigalarmed = 0;
  563.         
  564.         if (info -> timeout_in_secs > 0) {
  565.             alarm(info -> timeout_in_secs);
  566.             PP_TRACE(("alarm set for %d secs",
  567.                   info -> timeout_in_secs));
  568.         }
  569.         if (setjmp(pipe_alrm_jmp) != DONE) {
  570.             send_to_child(orig, fd[1], info->solo);
  571.             (void) close(fd[1]);
  572.         } else {
  573.             if (sigalarmed)
  574.                 PP_TRACE(("alarm went off"));
  575.             if (sigpiped)
  576.                 PP_TRACE(("pipe went off"));
  577.         }
  578.  
  579.         if (sigpiped) { /* pipe died - reset for timeout */
  580.             sigpiped = 0;
  581.             if (setjmp (pipe_alrm_jmp) == DONE)
  582.                 PP_TRACE(("Timeout"));
  583.         }
  584.  
  585.         if (sigalarmed) { /* alarm went off */
  586.             PP_NOTICE (("Process taking too long ... killing"));
  587.             (void) sprintf(buf,
  588.                        "Process took to long - killed");
  589.             killed = 1;
  590.             (void) killpg (pid, SIGTERM);
  591.             sleep(2);
  592.             (void) killpg (pid, SIGKILL);
  593.         }
  594.         do_child_logging (fd_stderr[0]);
  595.  
  596.         while ((pgmresult = wait(&w)) != pid && pgmresult != -1)
  597.             PP_TRACE(("process %d returned", pgmresult));
  598.  
  599.         alarm(0);
  600.  
  601.         PP_TRACE(("pid %d term=%d retcode=%d core=%d killed=%d",
  602.               pid, WTERMSIG(w), WEXITSTATUS(w),
  603.               WCOREDUMP(w), killed));
  604.  
  605.         (void) signal (SIGPIPE, oldpipe);
  606.         (void) signal (SIGALRM, oldalarm);
  607.         do_child_logging(fd_stderr[0]);
  608.         (void) close(fd[1]);
  609.         (void) close (fd_stderr[0]);
  610.         
  611.         if (pgmresult == pid && !killed && WIFEXITED(w) && rp_gbval(WEXITSTATUS(w)) == RP_BNO)
  612.             err_fatal = TRUE;
  613.  
  614.         if ((pgmresult == pid) && (WEXITSTATUS(w) == 0) && (killed == 0))
  615.             result = OK;
  616.         else 
  617.             result = NOTOK;
  618.     }
  619.  
  620.     free(expanded);
  621.     return result;
  622. }
  623.  
  624. static int do_child_logging(fd)
  625. int    fd;
  626. {
  627.     fd_set    rfds, ifds;
  628.     char    buf[80];    /* smallish */
  629.     int    n;
  630.     struct timeval timer;
  631.     char    *newfatal;
  632.     timerclear(&timer);
  633.  
  634.     PP_TRACE (("suckuperrors (%d)", fd));
  635.     FD_ZERO (&rfds);
  636.     FD_SET (fd, &rfds);
  637.  
  638. #define the_universe_exists    1
  639.  
  640.     while (the_universe_exists) {
  641.         ifds = rfds;
  642.  
  643.         if (select (fd + 1, &ifds, NULLFD, NULLFD, &timer) <= 0)
  644.             break;
  645.  
  646.         PP_TRACE (("select fired"));
  647.         if (FD_ISSET (fd, &ifds)) {
  648.             if((n = read (fd, buf, sizeof buf - 1)) > 0) {
  649.                 buf[n] = 0;
  650.                 PP_LOG (LLOG_EXCEPTIONS,
  651.                     ("Output from process '%s'", buf));
  652.                 if (fatalbuf == NULLCP)
  653.                     fatalbuf = strdup(buf);
  654.                 else {
  655.                     newfatal = malloc(strlen(fatalbuf) + strlen(buf) + 1);
  656.                     strcat (newfatal, fatalbuf);
  657.                     strcat (newfatal, buf);
  658.                     free(fatalbuf);
  659.                     fatalbuf = newfatal;
  660.                 }
  661.             }
  662.             else break;
  663.         }
  664.         else    break;
  665.     }
  666. }
  667.  
  668. static SFD alarmed(sig)
  669. int sig;
  670. {
  671.     sigalarmed = 1;
  672.     longjmp(pipe_alrm_jmp, DONE);
  673. }
  674.  
  675. static SFD piped (sig)
  676. int sig;
  677. {
  678.     sigpiped = 1;
  679.     longjmp(pipe_alrm_jmp, DONE);
  680. }
  681.  
  682. /*   */
  683. static int write_to_child(file, fd_out)
  684. char    *file;
  685. int    fd_out;
  686. {
  687.     char    buf[BUFSIZ];
  688.     int    fd_in,
  689.         num;
  690.  
  691.     if ((fd_in = open(file, O_RDONLY, 0666)) == -1) {
  692.         PP_SLOG(LLOG_EXCEPTIONS, file,
  693.                ("Can't open file"));
  694.         return NOTOK;
  695.     }
  696.  
  697.     while ((num = read(fd_in, buf, BUFSIZ)) > 0) {
  698.         if (write (fd_out, buf, num) == -1) {
  699.             (void) close(fd_in);
  700.             return NOTOK;
  701.         }
  702.         data_bytes += num;
  703.     }
  704.     (void) close(fd_in);
  705.     return OK;
  706. }
  707.                
  708. static ADDR *getnthrecip(que, num)
  709. Q_struct    *que;
  710. int        num;
  711. {
  712.     ADDR *ix = que->Raddress;
  713.  
  714.     if (num == 0)
  715.         return que->Oaddress;
  716.     while ((ix != NULL) && (ix->ad_no != num))
  717.         ix = ix->ad_next;
  718.     return ix;
  719. }
  720.  
  721.  
  722. static char    *get_adrstr(adr)
  723. ADDR    *adr;
  724. {
  725.     char    *key;
  726.     switch (adr->ad_type) {
  727.         case AD_X400_TYPE:
  728.         key = adr->ad_r400adr;
  729.         break;
  730.         case AD_822_TYPE:
  731.         key = adr->ad_r822adr;
  732.         break;
  733.         default:
  734.         key = adr->ad_value;
  735.         break;
  736.     }
  737.     return key;
  738. }
  739.  
  740. static int is822hdr(file)
  741. char    *file;
  742. {
  743.     char *ix = rindex(file, '/');
  744.  
  745.     if (ix == NULL
  746.         || (strncmp((ix+1),"hdr.822",strlen("hdr.822")) != 0))
  747.         return FALSE;
  748.     else
  749.         return TRUE;
  750. }
  751.  
  752. static int send_to_child(orig, fd, solo)
  753. char    *orig;
  754. int    fd;
  755. int    solo;
  756. {
  757.     int    result = OK;
  758.     char    file[MAXPATHLENGTH];
  759.     SFP    old_sig;
  760.         
  761.     pipe_signaled = FALSE;
  762.  
  763.     /* set signal handler */
  764.     old_sig = signal (SIGPIPE, sig_pipe);
  765.  
  766.     /* set long jump */
  767.     setjmp(toplevel);
  768.  
  769.     if (solo == TRUE)
  770.         result = write_to_child(orig, fd);
  771.     else {
  772.         msg_rinit(orig);
  773.  
  774.         while (pipe_signaled == FALSE
  775.                && msg_rfile(file) == RP_OK) {
  776.             write_to_child(file, fd);
  777.             if (is822hdr(file) == TRUE) {
  778.                 write(fd, "\n", 1);
  779.                 data_bytes ++;
  780.             }
  781.         }
  782.  
  783.         msg_rend();
  784.     }
  785.     /* unset signal handler */
  786.     signal (SIGPIPE, old_sig);
  787.  
  788.     return result;
  789. }    
  790.